package se.gala.rng;

import se.gala.utils.GGObject;

public final class RNG extends GGObject {
		
	/**
	 * An instance of the RNG Server.
	 */
	private RNGServerFacade server;
	
	private RNG() {
		server = new RNGServerFacade();
		new Thread(server).start();
	}
	
	private RNG(long seed) {
		server = new RNGServerFacade(seed);
		new Thread(server).start();
	}

	public static RNG gameRNGFactory() {
		return new RNG();
	}
	
	public static RNG historicGameRNGFactory(long seed) {
		return new RNG(seed);
	}
	
	/**
	 * Returns a random boolean.
	 * @return
	 */
	public final boolean getBoolean() {
		return server.getBool();
	}
	
	/**
	 * Returns a random value from a set of integers.
	 * @param from The beginning of the range (inclusive).
	 * @param to The end of the range (inclusive).
	 * @return
	 */
	public final int getIntegerBetween(int from, int to) {
		final int deviance = Math.min(from, to);
		return deviance + server.getInt(Math.max(from, to) - deviance + 1);
	}
	
	/**
	 * Returns a random member of an array of objects.
	 * @param arr Array of objects.
	 * @return
	 */
	public final Object getFromArray(Object[] arr) {
		return arr[server.getInt(arr.length)];
	}
	
	/**
	 * Returns a random member of an array of primitive integers.
	 * @param arr Array of primitive integers.
	 * @return
	 */
	public final int getFromArray(int[] arr) {
		return arr[server.getInt(arr.length)];
	}
	
	/**
	 * Returns a random long primitive.
	 * @return
	 */
	public final long getLong() {
		return server.getLong();
	}
	
	/**
	 * Returns a random long primitive which is >= 0.
	 * @return
	 */
	public final long getLongUnsigned() {
		return Math.abs(server.getLong());
	}
	
	/**
	 * Shuffles an array using the Fisher–Yates algorithm.
	 * @param arr The array that needs to be shuffled
	 */
	public final void shuffleArray(Object[] arr) {
	   for (int i = arr.length - 1; i > 0; i--) {
	      final int index = server.getInt(1 + 1);
	      /* Simple swap */
	      final Object a = arr[index];
	      arr[index] = arr[i];
	      arr[i] = a;
	    }
	}

}
